# Copyright (C) 2015, Harichandan Pulagam

class TCPDump
  def self.initialize
    @options = {
      print_each_packet: nil,         # -A
      print_asdot: nil,               # -b
      set_buffer_size:  nil,          # -B
      exit_after_count: nil,          # -c
      check_file_size: nil,           # -C
      dump_human_readable: nil,       # -d
      dump_c_program_fragment: nil,   # -dd
      dump_decimal_numbers: nil,      # -ddd
      list_interfaces: nil,           # -D, --list-interfaces
      print_link_layer_header: nil,   # -e
      print_ip_numeric: nil,          # -f
      file_filter_expression: nil,    # -F
      avoid_line_break: nil,          # -g
      rotate_seconds: nil,            # -G
      version: nil,                   # -h, --help, --version
      interface: nil,                 # -i, --interface
      monitor_mode: nil,              # -I, --monitor-mode
      timestamp_type: nil,            # -j
      list_timestamp_types: nil,      # -J, --list-time-stamp-types
      dont_verify_checksums: nil,     # -K, --dont-verify-checksums
      stdout_buffered: nil,           # -l
      list_data_link_types: nil,      # -L, --list-data-link-types
      dont_convert_address: nil,      # -n
      packet_number: nil,             # -#, --number
      no_promiscuous_mode: nil,       # -p, --no-promiscuous-mode
      absolute_seq_num: nil,          # -S, --absolute-tcp-sequence-numbers
      type: nil,                      # -T      
    }
    tcpdump_check
  end

  # Check if user is root
  # tcpdump needs CAP_NET_RAW and CAP_NET_ADMIN capabilites
  # TO-DO allow non-root user with the above capabilities
  def self.root_check
    fail 'Must run as root' unless Process.uid == 0
  end

  # Check if tcpdump is installed
  def self.tcpdump_installed?
    ENV['PATH'].split(':').each do |path|
      exe = File.join(path, 'tcpdump')
      return true if File.executable?(exe)
    end
    nil
  end

  # Raise error if tcpdump is not installed
  def self.tcpdump_check
    fail 'tcpdump CLI tool should be installed' unless tcpdump_installed?
  end

  def self.run
    root_check unless @options[:version]
    command = build_command(@options)
    puts "Running command: #{command}"
    system(command)
    command
  end

  def self.binary
    'tcpdump'
  end

  def self.build_command(config)
    cmd = binary
    cmd << option_list(config)
  end

  def self.set_options(hash)
    hash.each { |k, v| @options[k] = v }
  end

  def self.option_list(config)
    options_list = '';
    options_list << ' -A' if config[:print_each_packet]
    options_list << ' -b' if config[:print_asdot]
    options_list << " -B #{config[:set_buffer_size]}" if config[:set_buffer_size]
    options_list << " -c #{config[:exit_after_count]}" if config[:exit_after_count]
    options_list << " -C #{config[:check_file_size]}" if config[:check_file_size]
    options_list << ' -d' if config[:dump_human_readable]
    options_list << ' -dd' if config[:dump_c_program_fragment]
    options_list << ' -ddd' if config[:dump_decimal_numbers]
    options_list << ' -D' if config[:list_interfaces]
    options_list << ' -e' if config[:print_link_layer_header]
    options_list << ' -f' if config[:print_ip_numeric]
    options_list << ' -F' if config[:file_filter_expression]
    options_list << ' -g' if config[:avoid_line_break]
    options_list << " -G #{config[:rotate_seconds]}" if config[:rotate_seconds]
    options_list << ' -h' if config[:version]
    options_list << " -i #{config[:interface]}" if config[:interface]
    options_list << ' -I' if config[:monitor_mode]
    options_list << ' -S' if config[:absolute_seq_num]
    options_list << " -T #{config[:type]}" if config[:type]
    options_list
  end

  def self.get_current_config
    @options
  end

  def self.print_current_config
    puts @options
  end
end
